【视频讲解】Scrapy递归抓取简书用户信息
https://v.qq.com/txp/iframe/player.html?vid=e0524pyrzv7&width=500&height=375&auto=0
https://v.qq.com/txp/iframe/player.html?vid=j05242y2g8s&width=500&height=375&auto=0
好久没有录制实战教程视频,大邓就在圣诞节后直接上干货。
之前写过一期【视频教程-用python批量抓取简书用户信息】的文章,是自己造的轮子,今天我趁着刚入门scrapy和xpath,操刀重写这个任务。
一、实战项目简介
递归
我们要大批量获取简书网站上的用户数据,最直接的办法是给一个初识的用户url,从这个用户的关注的和粉丝中再抽取url,循环往复,周而复始。这其实就是递归。
#注意我们一开始要研究的网址里是u,而不是user
https://www.jianshu.com/u/811ae6268caa
数据项
获取到的url,我们需要对其进行请求,解析出想要的数据
昵称-nickname
关注数-followed
粉丝数- following
文章数-articles
文字数-charlength
喜欢数-likes
二、创建scrapy项目
2.1 创建项目
打开pycharm,点击左下角的terminal(mac上是这样,win应该类似)
scrapy startproject JianShu
2.2 生成爬虫
在terminal中我们要切换到项目文件夹中,在这里是JianShu文件夹,代码如下
cd JianShu
然后生成爬虫,注意爬虫名不能与项目名相同。
scrapy genspider 爬虫名 域名
scrapy genspider jianshu https://www.jianshu.com
三、构建爬虫各功能模块
scrapy爬虫框架,概括起来是
spider下的爬虫脚本负责业务逻辑,发起请求,解析数据。
middleware负责对爬虫进行伪装或者加代理
item将爬虫脚本中的请求解析的数据封装到数据容器
并传递给pipeline以保存到csv、txt或者数据库中去。
settings存储项目各种参数
main主程序,运行开始爬数据
3.1 伪装请求头
一般为了让爬虫更健壮,我肯定不会跟网站说我是爬虫害虫,而是说我是好人,我来自浏览器人类的请求。
在scrapy中,我们先在settings.py中加入多个浏览器User-Agent,取消DOWNLOADER_MIDDLEWARES的前的注释。为了方便理解,我将里面的名字改成了HeadersMiddleware。
注意这里一定要DOWNLOADER_MIDDLEWARES字典中的value值写小一点,比如400。为了这个参数,我写好的没错的爬虫死活不运行,还总是403错误!!!!
DOWNLOADER_MIDDLEWARES = {
'jianshu.middlewares.HeadersMiddleware': 400}
UserAgentList = ["Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;","Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)"]
然后在middleware.py中,定义我们的中间件。
from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware
from jianshu.settings
import UserAgentList
import random
class HeadersMiddleware(UserAgentMiddleware):
"""
给请求随机加入伪装头headers
"""
def process_request(self, request, spider):
ua = random.choice(UserAgentList)
request.headers.setdefault('User-Agent:', ua)
3.2 item容器-整理数据
我们可以将item理解成存储数据的容器,类似于字典。只不过这个字典可以还有很多功能,可以在scrapy中飞来飞去的。挺神奇的。
from scrapy import Item,Field
class JianshuItem(Item):
nickname = Field()
description = Field()
followed = Field()
following = Field()
articles = Field()
charlength = Field()
likes = Field()
3.3 pipeline-存储到csv文件中
数据库我不太熟,直接用csv这种人见人会的方式保存数据吧。
经过item整理后的数据,我们就可以通过pipeline保存到csv中去。
首先打开pipelines.py文件
import csv
class CSVPipeline(object):
def __init__(self):
self.csvf = open('data.csv', 'a+', encoding='gbk', newline='')
self.writer = csv.writer(self.csvf)
self.writer.writerow(('nickname', 'description', 'followed', 'fpllowing', 'articles', 'charlength', 'likes'))
self.csvf.close()
def process_item(self, item, spider):
with open('data.csv', 'a+', encoding='gbk', newline='') as f:
writer = csv.writer(f)
writer.writerow((item['nickname'], item['description'], item['followed'], item['following'], item['articles'], item['charlength'], item['likes']))
return item
再打开settings.py,取消ITEM_PIPELINES注释。让item与pipeline完美衔接,一个负责整理数据,一个负责保存数据。
ITEM_PIPELINES = {
'JianShu.pipelines.CSVPipeline': 300,}
四、编写爬虫
前面的所有工作都是准备工作,我个人喜欢先做前面,做好后再编写爬虫。看个人喜好,其实你们如果愿意,也可以先写爬虫再写item、pipeline、middleware、settings。
4.1 解析数据
这里我们用到xpath解析,上一期的公众号文章已经分享,就不做仔细介绍了。大家不懂的就看看上一期文章。
注意,response.xpath()得到的是selector对象(而且是selector列表),selector对象有extract方法。所以
nickname = response.xpath("//div[@class='main-top']/div[@class='title']/a/text()").extract()[0]
#返回li的selector对象列表
info_selectors = response.xpath("//div[@class='main-top']/div[@class='info']/ul/li")
followed_url = 'https://www.jianshu.com'+info_selectors[0].xpath("./div/a/@href").extract()[0]
followed = info_selectors[0].xpath("./div/a/p/text()").extract()[0]following = info_selectors[1].xpath("./div/a/p/text()").extract()[0]
articles = info_selectors[2].xpath("./div/a/p/text()").extract()[0]charlength = info_selectors[3].xpath("./div/p/text()").extract()[0]
likes = info_selectors[4].xpath("./div/p/text()").extract()[0]
description = re.sub('\s','',''.join(response.xpath("//div[@class='js-intro']/text()").extract()))
补充。
#将string字符串中的pattern1替换成pattern2
re.sub(pattern1,pattern2,string)
4.2 关注列表解析
上面的解析都是一个人的关注、粉丝、文章数等信息的提取。其实我们为了递归批量获取简书用户信息,还需要大量的用户url。
而大量的用户url,最好的来源便是从关注与粉丝对应的用户列表中解析。
经过抓包发现
pages = int(float(followed)/10)
for page in range(1,pages+1):
userlist_url = followed_url + '?page={page}'.format(page=page)
yield Request(userlist_url, callback=self.parseuserlist, dont_filter=True)
def parseuserlist(self,response):
url_list = response.xpath("//ul[@class='user-list']/li/div[@class='info']/a/@href").extract()
url_list = ['https://www.jianshu.com'+url for url in url_list]
yield Request(url,callback=self.parse,dont_filter=True)
整理汇总爬虫-jianshu.py
from scrapy import Spider, Request
from JianShu.items import JianshuItem
import re
class JianshuSpider(Spider):
name = 'jianshu'
allowed_domains = ['https://www.jianshu.com']
start_urls = ['https://www.jianshu.com/u/cf09bc3817a7']
def start_requests(self):
start_url = 'https://www.jianshu.com/u/811ae6268caa'
yield Request(start_url, callback=self.parse)
def parse(self, response):
item = JianshuItem()
nickname = response.xpath("//div[@class='main-top']/div[@class='title']/a/text()").extract()[0]
info_selectors = response.xpath("//div[@class='main-top']/div[@class='info']/ul/li")
followed_url = 'https://www.jianshu.com'+info_selectors[0].xpath("./div/a/@href").extract()[0]
followed = info_selectors[0].xpath("./div/a/p/text()").extract()[0]
pages = int(float(followed)/10)
for page in range(1,pages+1):
userlist_url = followed_url + '?page={page}'.format(page=page)
yield Request(userlist_url, callback=self.parseuserlist, dont_filter=True)
following_url = 'https://www.jianshu.com' + info_selectors[1].xpath("./div/a/@href").extract()[0]
following = info_selectors[1].xpath("./div/a/p/text()").extract()[0]
articles_url = 'https://www.jianshu.com' + info_selectors[2].xpath("./div/a/@href").extract()[0]
articles = info_selectors[2].xpath("./div/a/p/text()").extract()[0]
charlength = info_selectors[3].xpath("./div/p/text()").extract()[0]
likes = info_selectors[4].xpath("./div/p/text()").extract()[0]
description = re.sub('\s','',''.join(response.xpath("//div[@class='js-intro']/text()").extract()))
item['nickname'] = nickname
item['description'] = description
item['followed'] = followed
item['following'] = following
item['articles'] = articles
item['charlength'] = charlength
item['likes'] = likes
yield item
def parseuserlist(self,response):
url_list = response.xpath("//ul[@class='user-list']/li/div[@class='info']/a/@href").extract()
url_list = ['https://www.jianshu.com'+url for url in url_list]
for url in url_list:
yield Request(url,callback=self.parse,dont_filter=True)
五、开始爬爬爬
为了方便测试,后期运行,我们在项目跟目录定制了main.py文件
5.1 main.py
直接在此更改,点击运行即可爬数据。
from scrapy.cmdline import execute
import os,sys
sys.path.append(os.path.dirname(os.path.basename(__file__)))
#注意,jianshu是爬虫名,不是项目名
execute(['scrapy','crawl','jianshu'])
5.2 运行效果
5.3 代码下载地址
链接: https://pan.baidu.com/s/1o8kkF1K 密码: hmpj
支持大邓
数据采集
【视频】有了selenium,小白也可以自豪的说:“去TMD的抓包、cookie”
【视频】快来get新技能--抓包+cookie,爬微博不再是梦